/* 算法实现模板 */
import { toVector } from "../../common/Vector";
import AlgorithmBase from "./AlgorithmBase";
import katex from "katex";
import Figure2D from "../../visual/Figure2D";
import { drawKDTree } from "../../visual/Tree2D";
// KDTree
import { createKDNode, NodeRange, calcNodeRange, KDNode } from "../../common/KDTreeFuncs";

import DefaultValue from './input/KDTree.input.json';

class KDTree extends AlgorithmBase{
  constructor(){
    super('KDTree');

    // 初始化图
    const figure = new Figure2D(600, 450);
    figure.xMax = 10.0;
    figure.xMin = 0.0;
    figure.yMax = 10.0;
    figure.yMin = 0.0;
    figure.gridX = 12;
    figure.gridY = 12;
    
    this.figure = figure;

    this.DefaultValue = DefaultValue;
  }

  init(){
    this.loadModel(this.DefaultValue);

    if(this.domFigure) {
      this.domFigure.innerHTML = '';
      this.domFigure.appendChild(this.figure.domElement);
    }

    if(this.figure) this.figure.clearAll();
    this.print();
  }

  train(){
    const T = this.trainDS.T;
    let node = createKDNode(0, T);

    this.model.node = node;

    if(this.figure) this.figure.clearAll();
    this.print();
  }

  loadModel(json){
    if(json.TrainDS){
      this.trainDSList = [];
      if(json.TrainDS instanceof Array){
        for(let i = 0, il = json.TrainDS.length; i < il; i++){
          const newTrain = json.TrainDS[i];
          newTrain.T = toVector(newTrain.T, true);
          this.trainDSList.push(newTrain);
        }
        this.trainDS = this.trainDSList[0];
      }
      else{
        this.trainDS.T = toVector(json.TrainDS.T, true);
      }
    }

    this.model.node = new KDNode();
  }

  load(jsonString){
    let json = JSON.parse(jsonString);
    if(json.TrainDS){
      let tmp = JSON.parse(json.TrainDS);
      this.trainDS.T = toVector(tmp.T, true);
    }
    if(json.Model){
      let tmp = JSON.parse(json.Model);
      let node = new KDNode();
      node.copyFromJSON(tmp.node);
      this.model.node = node;
    }
    
    if(this.figure) this.figure.clearAll();
    this.print();
  }

  displayTrain(){
    const T = this.trainDS.T;
    if(this.domTrain){
      let katexString = String.raw`\{`;
      for(let i = 0, il = T.length; i < il; i++){
        katexString += T[i].toKatexString();
        if(i !== il - 1){
          katexString += ',';
        }
        if(this.figure){
          const point = T[i];
          if(point.length === 2){
            this.figure.addPoint(point[0], point[1]);
          }
        }
      }
      katexString += String.raw`\}`;
      katex.render(katexString, this.domTrain, { throwOnError: false });
    }
    // 绘制点到图
    if(this.figure){
      this.figure.update();
    }
  }

  drawSplitLine(node){

    if(!node || !node.dom_elt) return;
    // if(!node.left && !node.right) return;
    
    const dom_elt = node.dom_elt;
    if(!this.figure) return;
    
    if(node.split === 0){
      this.figure.addLine([dom_elt[0], node.sMin], [dom_elt[0], node.sMax]);
    }
    else{
      this.figure.addLine([node.sMin, dom_elt[1]], [node.sMax, dom_elt[1]]);
    }

    this.drawSplitLine(node.left);
    this.drawSplitLine(node.right);

    this.figure.update();
  }

  displayModel(){
    let node = this.model.node;
    
    if(this.figure){
      let range = new NodeRange([[this.figure.xMin, this.figure.xMax + 1],[this.figure.yMin,this.figure.yMax + 1]]);

      calcNodeRange(node, range);
      // 绘制分割线
      this.drawSplitLine(node);
      this.figure.update();
    }

    if(this.domModel) this.domModel.innerHTML = '';
    drawKDTree(this.domModel, node);
  }

  setTrainDS(index){
    if(index < 0 || index >= this.trainDSList.length) return ;
    this.trainDS = this.trainDSList[index];
    this.model.node = new KDNode();

    if(this.figure) this.figure.clearAll();
    this.displayModel();
  }

  test(){
    this.print();
  }
}


export default KDTree;